package in.smartbillpay.web.controllers;

import in.smartbillpay.web.models.Authority;
import in.smartbillpay.web.models.City;
import in.smartbillpay.web.models.District;
import in.smartbillpay.web.models.SBPUser;
import in.smartbillpay.web.models.State;
import in.smartbillpay.web.services.AuthorityService;
import in.smartbillpay.web.services.LocationService;
import in.smartbillpay.web.services.UserService;
import in.smartbillpay.web.validators.FormPostResponse;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

/**
 * Handles requests for the user registration.
 */
@Controller
@RequestMapping("/public/register")
public class RegisterController {
	
	private static final Logger logger = LoggerFactory.getLogger(RegisterController.class);
	

	@Autowired
	private LocationService locationService;
	
	 @Autowired
	 private PasswordEncoder passwordEncoder;
	
	 @Autowired
	 private SaltSource saltSource;
	
	 @Autowired
	private UserService userService;
	
	@Autowired
	private AuthorityService authorityService;
	
	/**
	 * Returns the Registration form for Agent
	 */
	@RequestMapping(value = "/agent", method = RequestMethod.GET)
	public ModelAndView getAgentRegistrationForm() {
		logger.info("Inside getAgentRegistrationForm()");
		ModelAndView mav = new ModelAndView("regsiter_agent");
		// Command object
		SBPUser user = new SBPUser();
		mav.addObject("user", user );
		
		// get the state list
		List<State> stateList = locationService.getAllState();
		mav.addObject("stateList", stateList);
		int defaultStateId = stateList.get(0).getId();
		for (State state : stateList) {
			if(state.getName().equalsIgnoreCase("Maharashtra")){
				defaultStateId = state.getId();
				break;
			}
		}
		mav.addObject("defaultStateId", defaultStateId);
		List<District> districtList = locationService.getDistricts(defaultStateId);
		mav.addObject("districtList", districtList);
		
		int defaultDistrictId = districtList.get(0).getId();
		for (District district : districtList) {
			if(district.getName().equalsIgnoreCase("Pune")){
				defaultDistrictId = district.getId();
				break;
			}
		}
		// get the district list
		mav.addObject("defaultDistrictId", defaultDistrictId);
		List<City> cityList = locationService.getCities(defaultDistrictId);
		mav.addObject("cityList", cityList);
			 
		
		return mav;
	}
	
	
	/**
	 * checks if the requested UserName is available
	 */
	@RequestMapping(value = "/isuniqueuser", method = RequestMethod.GET)
	public @ResponseBody boolean isUserIdAvailable(@RequestParam String username ) {
		logger.info("Inside isUserIdAvailable()");
		
		List<SBPUser> userList = getUserService().getUserByName(username);
		if(userList.size() > 0) {
			logger.info("userName is already in use");
			return false;
		}
		else {
			logger.info("userName is available");
			return true;
		}		
	}
	
	/**
	 * Save the new user record
	 */
	@RequestMapping(value = "/agent", method = RequestMethod.POST)
	public @ResponseBody FormPostResponse registerNewUser(@Valid SBPUser user,BindingResult result ) {
		logger.info("Inside isUserIdAvailable()");
		FormPostResponse response = new FormPostResponse();
		//	districtValidator.validate(district, result);
			if(result.hasErrors()){
				Map<String,String> errorMap = new HashMap<String,String>();
				response.setErrorMap(errorMap);
				for(FieldError error:result.getFieldErrors() ){
					
					errorMap.put("errorMessage", error.getDefaultMessage());
					logger.info(error.getField() + " " + error.getDefaultMessage());
				}
					
				response.setStatus("error");
				logger.info(Integer.toString(result.getErrorCount()));
			}
			else{
				// set registration date to today's date
				user.setRegisterDate(new Date());
				// set LastUpdateDate date to today's date
				user.setLastUpdateDate(new Date());
				// set TerminationDate to a year ahead
				Calendar calendar = Calendar.getInstance();
				calendar.set(Calendar.YEAR +1, Calendar.MONTH, Calendar.DATE);
				Date terminationDate = calendar.getTime();
				logger.info(terminationDate.toString());
				user.setTerminationDate(terminationDate);
				// set the Enabled field to true so that user can login
				user.setEnabled(true);
				// set the default status to Enrolled
				user.setStatus("Enrolled");
				// set the authority
				List<Authority> authorityList = authorityService.getByName("ROLE_AGENT");
				if(authorityList.size() > 0) {
					user.setAuthorityList(authorityList);
				}
				
				// encode the password
				logger.info("plain text password -" + user.getPassword());
				 String encodedPassword =passwordEncoder.encodePassword(user.getPassword(), saltSource.getSalt(user));
				 logger.info("encoded password -" + encodedPassword);
				 user.setPassword(encodedPassword);
				 
				getUserService().saveOrUpdate(user);
				Map<String,String> resultMap = new HashMap<String,String>();
				resultMap.put("userName", user.getUsername());
				response.setStatus("Success");
				response.setResultMap(resultMap);
				
			}
			
			return  response;
		
	}
	
	/**
	 * @return the locationService
	 */
	public LocationService getLocationService() {
		return locationService;
	}

	/**
	 * @param locationService the locationService to set
	 */
	public void setLocationService(LocationService locationService) {
		this.locationService = locationService;
	}

	/**
	 * @return the userService
	 */
	public UserService getUserService() {
		return userService;
	}

	/**
	 * @param userService the userService to set
	 */
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	public AuthorityService getAuthorityService() {
		return authorityService;
	}

	public void setAuthorityService(AuthorityService authorityService) {
		this.authorityService = authorityService;
	}
	/**
	 * @return the passwordEncoder
	 */
	public PasswordEncoder getPasswordEncoder() {
		return passwordEncoder;
	}
	/**
	 * @param passwordEncoder the passwordEncoder to set
	 */
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}
	/**
	 * @return the saltSource
	 */
	public SaltSource getSaltSource() {
		return saltSource;
	}
	/**
	 * @param saltSource the saltSource to set
	 */
	public void setSaltSource(SaltSource saltSource) {
		this.saltSource = saltSource;
	}
}
